{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import panel as pn\n",
    "\n",
    "pn.extension()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``DataFrame`` pane renders pandas, dask and streamz ``DataFrame`` and ``Series`` types as an HTML table. The Pane supports all the arguments to the `DataFrame.to_html` function. \n",
    "\n",
    "If you need to to display a larger `DataFrame` or use advanced table features and interactivity we recommend using the [`Tabulator`](../widgets/Tabulator.ipynb) widget or [`Perspective`](Perspective.ipynb) pane instead.\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "For details on other options for customizing the component see the [layout](../../how_to/layout/index.md) and [styling](../../how_to/styling/index.md) how-to guides.\n",
    "\n",
    "* **``bold_rows``** (boolean, default=True): Make the row labels bold in the output.\n",
    "* **``border``** (int, default=0): Width of the border included in the opening ``table`` tag.\n",
    "* **``classes``** (list[str]): CSS class(es) to apply to the resulting html table.\n",
    "* **``col_space``** (int, str or dict): The minimum width of each column in CSS length units. An int is assumed to be px units.\n",
    "* **``decimal``** (str, default='.'): Character recognized as decimal separator, e.g. ',' in Europe.\n",
    "* **``escape``** (boolean, default=True): Convert the characters <, >, and & to HTML-safe sequences.\n",
    "* **``float_format``** (function): Formatter function to apply to columns' elements if they are floats. The result of this function must be a unicode string.\n",
    "* **``formatters``** (dict or list): Formatter functions to apply to columns' elements by position or name. The result of each function must be a unicode string.\n",
    "* **``object``** (object): The DataFrame object being displayed\n",
    "* **``header``** (boolean, default=True): Whether to print column labels.\n",
    "* **``index``** (boolean, default=True): Whether to print index (row) labels.\n",
    "* **``index_names``** (boolean, default=True): Whether to print the names of the indexes.\n",
    "* **``justify``** (str): How to justify the column labels ('left', 'right', 'center', 'justify', 'justify-all', 'start', 'end', 'inherit', 'match-parent', 'initial', 'unset')\n",
    "* **``max_rows``** (int): Maximum number of rows to display.\n",
    "* **``max_cols``** (int): Maximum number of columns to display.\n",
    "* **``na_rep``** (str, default='NaN'): String representation of NAN to use.\n",
    "* **``render_links``** (boolean, default=False): Convert URLs to HTML links.\n",
    "* **``show_dimensions``** (boolean, default=False): Display DataFrame dimensions (number of rows by number of columns).\n",
    "* **``sparsify``** (boolean, default=True): Set to False for a DataFrame with a hierarchical index to print every multi-index key at each row.\n",
    "* **``text_align``** (str): How to justify the non-header cells ('left', 'right', 'center')\n",
    "\n",
    "___"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `DataFrame` uses the inbuilt HTML repr to render the underlying DataFrame:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.DataFrame({\n",
    "    'int': [1, 2, 3],\n",
    "    'float': [3.14, 6.28, 9.42],\n",
    "    'str': ['A', 'B', 'C'],\n",
    "    'bool': [True, False, True],\n",
    "}, index=[1, 2, 3])\n",
    "\n",
    "df_pane = pn.pane.DataFrame(df, width=400)\n",
    "\n",
    "df_pane"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Like all other Panel objects changing a parameter will update the view allowing us to control the styling of the dataframe. In this example we will control these parameters using a set of widgets created directly from Pane:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.panel(df_pane.param, parameters=['bold_rows', 'index', 'header', 'max_rows', 'show_dimensions'],\n",
    "         widgets={'max_rows': {'start': 1, 'end': len(df), 'value': len(df)}})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By setting `escape` to False you can include *HTML markup* in your `Dataframe` pane"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "links = pd.DataFrame({\n",
    "    \"site\": [\"Docs\", \"Discourse\", \"Github\", \"Twitter\"], \n",
    "    \"url\": [\"https://panel.holoviz.org/\", \"https://discourse.holoviz.org/\", \"https://github.com/holoviz/panel\", \"https://twitter.com/Panel_org\"]\n",
    "})\n",
    "links[\"value\"]=\"<a href='\" + links[\"url\"] + \"' target='_blank'>\" + links[\"site\"] + \"</a>\"\n",
    "pn.pane.DataFrame(links, escape=False, width=800, index=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Larger DataFrames\n",
    "\n",
    "For larger dataframes it can be useful to set `sizing_mode=\"stretch_both\"` to make sure they don't *overflow*. When you do this, you can use `max_height` to specify the (maximum) height."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.sampledata.airport_routes import airports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "table = pn.pane.DataFrame(airports.head(50), sizing_mode=\"stretch_both\", max_height=300)\n",
    "table"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Column(\"## Header\", table, \"## Footer\", height=400, width=500).servable()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Streamz DataFrames\n",
    "\n",
    "In addition to rendering standard pandas `DataFrame` and `Series` types the `DataFrame` pane will also render updating `streamz` types.",
    "\n",
    "Note:\n",
    "\n",
    "- In a live kernel you should see the dataframe update every 0.5 seconds.\n",
    "- `streamz` does currently not work in Pyodide/PyScript."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from streamz.dataframe import Random\n",
    "\n",
    "sdf = Random(interval='200ms', freq='50ms')\n",
    "\n",
    "pn.pane.DataFrame(sdf, width=500)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(sdf.groupby('y').sum().x)"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
